﻿using System;
using Core.Extension;
using DG.Tweening;
using UnityEngine;

namespace Logic.Global
{
    /// 游戏相机控制器
    public class GameCamera : SingletonMono<GameCamera>
    {
        public Camera gameCamera;

        /// <summary>
        /// 相机宽度
        /// </summary>
        public float CameraWidth => gameCamera.orthographicSize * gameCamera.aspect * 2;

        /// <summary>
        /// 相机高度
        /// </summary>
        public float CameraHeigh => gameCamera.orthographicSize * 2;

        /// <summary>
        /// 相机的位置
        /// </summary>
        public Vector3 CameraPos => transform.position;

        /// <summary>
        /// 相机视野的左边界
        /// </summary>
        public float CurLeftBorder => CameraPos.x - CameraWidth / 2;

        /// <summary>
        /// 相机视野的右边界
        /// </summary>
        public float CurRightBorder => CameraPos.x + CameraWidth / 2f;

        /// <summary>
        /// 相机视野的上边界
        /// </summary>
        public float CurUpBorder => CameraPos.y + CameraHeigh / 2;

        /// <summary>
        /// 相机视野的下边界
        /// </summary>
        public float CurDownBorder => CameraPos.y - CameraHeigh / 2;

        /// <summary>
        /// 获取当前游戏相机视野中一个点的坐标
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public Vector2 GetPos(float x, float y)
        {
            Vector2 vec = new Vector2(x, y);
            Vector2 result = new Vector3(transform.position.x + CameraWidth / 2 * vec.x,
                transform.position.y + CameraHeigh / 2 * vec.y);
            return result;
        }

        /// <summary>
        /// 聚焦到某个对象
        /// </summary>
        /// <param name="target">目标对象</param>
        /// <param name="duration">时长</param>
        /// <param name="finishCb">完成时的回调</param>
        /// <param name="bindObj">所绑定的对象。当对象Destroy时，动画将会被杀死</param>
        public void FocusTo(Transform target, float duration = 0.5f, Action finishCb = null, GameObject bindObj = null)
        {
            FocusTo(target.position, duration, finishCb, bindObj);
        }

        /// <summary>
        /// 重置默认聚焦（0,0）
        /// </summary>
        /// <param name="duration">时长</param>
        /// <param name="finishCb">完成时的回调</param>
        /// <param name="bindObj">所绑定的对象。当对象Destroy时，动画将会被杀死</param>
        public void FocusReset(float duration = 0.5f, Action finishCb = null, GameObject bindObj = null)
        {
            FocusTo(Vector2.zero, duration, finishCb, bindObj);
        }

        private Tweener _cameraMoveTweener;
        private Tweener _cameraSizerTweener;

        /// <summary>
        /// 聚焦到某个坐标
        /// </summary>
        /// <param name="targetPos">目标位置</param>
        /// <param name="duration">时长</param>
        /// <param name="finishCb">完成时的回调</param>
        /// <param name="bindObj">所绑定的对象。当对象Destroy时，动画将会被杀死</param>
        public void FocusTo(Vector2 targetPos, float duration = 0.5f, Action finishCb = null, GameObject bindObj = null)
        {
            //添加遮罩，防止摄象机的异步被删除
            Util.OpenRayMask();
            if (_cameraMoveTweener != null) _cameraMoveTweener.Kill(true);
            Vector3 pos = new Vector3(targetPos.x, targetPos.y, gameCamera.transform.position.z);
            if (duration.Equals(0))
            {
                gameCamera.transform.position = pos;
                finishCb?.Invoke();
                return;
            }

            _cameraMoveTweener = gameCamera.transform.DOMove(pos, duration).OnComplete(delegate
            {
                finishCb?.Invoke();
            });
            if (bindObj != null) _cameraMoveTweener.SetLink(bindObj);
        }

        /// <summary>
        /// 调整相机的视口大小
        /// </summary>
        /// <param name="size">视口大小</param>
        /// <param name="duration">动画时长</param>
        /// <param name="finishCb">完成时的回调</param>
        /// <param name="bindObj">所绑定的对象。当对象Destroy时，动画将会被杀死</param>
        public void ResizeCamera(float size, float duration = 0.5f, Action finishCb = null, GameObject bindObj = null)
        {
            //添加遮罩，防止摄象机的异步被删除
            Util.OpenRayMask();
            if (_cameraSizerTweener != null) _cameraSizerTweener.Kill(true);
            if (gameCamera.orthographicSize.Equals(size))
            {
                finishCb?.Invoke();
                return;
            }

            if (duration.Equals(0))
            {
                gameCamera.orthographicSize = size;
                finishCb?.Invoke();
                return;
            }

            _cameraSizerTweener = gameCamera.DOOrthoSize(size, duration).OnComplete(delegate { finishCb?.Invoke(); });
        }

        /// <summary>
        /// 同时调整相机的视口大小和视口位置
        /// </summary>
        /// <param name="size">视口大小</param>
        /// <param name="targetPos"></param>
        /// <param name="duration">动画时长</param>
        /// <param name="finishCb">完成时的回调</param>
        /// <param name="bindObj">所绑定的对象。当对象Destroy时，动画将会被杀死</param>
        public void Set(float size, Vector2 targetPos, float duration = 0.5f, Action finishCb = null,
            GameObject bindObj = null)
        {
            Util.OpenRayMask();
            int finishCount = 0;
            FocusTo(targetPos, duration, delegate
            {
                finishCount++;
                if (finishCount >= 2)
                {
                    Util.CloseRayMask();
                    finishCb?.Invoke();
                }
            }, bindObj);
            ResizeCamera(size, duration, delegate
            {
                finishCount++;
                if (finishCount >= 2)
                {
                    Util.CloseRayMask();
                    finishCb?.Invoke();
                }
            }, bindObj);
        }
    }
}